using System;
using System.Reflection;
using System.Collections.Generic;


public sealed class Program {
   private const BindingFlags c_bf = BindingFlags.FlattenHierarchy |
      BindingFlags.Instance | BindingFlags.Static |
      BindingFlags.Public | BindingFlags.NonPublic;

   public static void Main() {
      // Show size of heap before doing any reflection stuff
      Show("Before doing anything");

      // Build cache of MethodInfo objects for all methods in MSCorlib.dll
      List<MethodBase> methodInfos = new List<MethodBase>();
      foreach (Type t in typeof(Object).Assembly.GetExportedTypes()) {
         // Skip over any generic types
         if (t.IsGenericTypeDefinition) continue;

         MethodBase[] mb = t.GetMethods(c_bf);
         methodInfos.AddRange(mb);
      }

      // Show number of methods and size of heap after binding to all methods
      Console.WriteLine("# of methods={0:###,###}", methodInfos.Count);
      Show("After building cache of MethodInfo objects");


      // Build cache of RuntimeMethodHandles for all MethodInfo objects
      List<RuntimeMethodHandle> methodHandles = 
         methodInfos.ConvertAll<RuntimeMethodHandle>(
            delegate(MethodBase mb) { return mb.MethodHandle; });

      Show("Holding MethodInfo and RuntimeMethodHandle cache");
      GC.KeepAlive(methodInfos); // Prevent cache from being GC'd early

      methodInfos = null;        // Allow cache to be GC'd now
      Show("After freeing MethodInfo objects");

      methodInfos = methodHandles.ConvertAll<MethodBase>(
         delegate(RuntimeMethodHandle rmh) { 
            return MethodBase.GetMethodFromHandle(rmh); });
      Show("Size of heap after re-creating MethodInfo objects");
      GC.KeepAlive(methodHandles);  // Prevent cache from being GC'd early
      GC.KeepAlive(methodInfos);    // Prevent cache from being GC'd early

      methodHandles = null;         // Allow cache to be GC'd now
      methodInfos = null;           // Allow cache to be GC'd now
      Show("After freeing MethodInfos and RuntimeMethodHandles");
   }

   private static void Show(String s) {
      Console.WriteLine("Heap size={0,12:##,###,###} - {1}", 
         GC.GetTotalMemory(true), s);
   }
}